home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / general / raytrace / rayshade / graphtal.lzh / Graphtal.Amiga / Turtle.C < prev    next >
C/C++ Source or Header  |  1992-11-17  |  7KB  |  310 lines

  1. /*
  2.  * Turtle.C - definitions for 3D turtle.
  3.  *
  4.  * Copyright (C) 1992, Christoph Streit (streit@iam.unibe.ch)
  5.  *                     University of Berne, Switzerland
  6.  * All rights reserved.
  7.  *
  8.  * This software may be freely copied, modified, and redistributed
  9.  * provided that this copyright notice is preserved on all copies.
  10.  *
  11.  * You may not distribute this software, in whole or in part, as part of
  12.  * any commercial product without the express consent of the authors.
  13.  *
  14.  * There is no warranty or other guarantee of fitness of this software
  15.  * for any purpose.  It is provided solely "as is".
  16.  *
  17.  */
  18.  
  19. #include <stdlib.h>
  20. #include <values.h>
  21. #include "Turtle.h"
  22. #include "TransMatrix.h"
  23. #include "Error.h"
  24. #include "Ray.h"
  25.  
  26. //___________________________________________________________ Tropism
  27.  
  28. Tropism::Tropism(real x, real y, real z, real w)
  29. : F(x, y, z), weight(w), apply(0)
  30. {
  31.   if (F.zero()) 
  32.     F = Vector(0,0,-1);
  33.   F.normalize();
  34. }
  35.  
  36. //___________________________________________________________ Turtle
  37.  
  38. /* init of turtle:
  39.  *
  40.  *                   *
  41.  *            / \ H
  42.  *             |
  43.  *                   |
  44.  *          L        |
  45.  *        / _________|
  46.  *        \         /
  47.  *                 / U
  48.  *               \ /
  49.  *                *
  50.  */                                          
  51.  
  52. Turtle::Turtle()
  53. : P(0,0,0), lastP(0,0,0), H(0,0,1), L(0,-1,0), U(1,0,0),
  54.   tropism(0,0,-1,0.5),
  55.   hullActivated(0), hull(NULL), reflectanceFactor(1), stopOnHit(0)
  56. {
  57.  width = 1;
  58.  lastWidth = -1; // no move has been previously done
  59.   
  60.  b.expand(P);
  61. }
  62.  
  63. Turtle::Turtle(const Turtle& t)
  64. :b(t.b), 
  65.  P(t.P), lastP(t.lastP), 
  66.  H(t.H), L(t.L), U(t.U),
  67.  width(t.width), lastWidth(t.lastWidth),
  68.  tropism(t.tropism),
  69.  color(t.color), lastColor(t.lastColor),
  70.  texture(t.texture), lastTexture(t.lastTexture),
  71.  hullActivated(t.hullActivated),
  72.  stopOnHit(t.stopOnHit),
  73.  hull(t.hull),
  74.  reflectanceFactor(t.reflectanceFactor),
  75.  closestObject(t.closestObject),
  76.  distanceToClosestObject(t.distanceToClosestObject)
  77. {}
  78.  
  79. Turtle::~Turtle()
  80. {}
  81.  
  82. /*
  83.  * forward moves the turtle in the current direction according to
  84.  * the formula:
  85.  *
  86.  *     P' = P + step*H
  87.  */
  88.  
  89. int Turtle::forward(real step)
  90. {
  91.   lastWidth = width;
  92.   lastP = P;
  93.   lastColor = color;
  94.   lastTexture = texture;
  95.  
  96.   if (hullActivated)
  97.     return forwardWithRespectToHull(step);
  98.   else {
  99.     P += step*H;
  100.     applyTropism();
  101.     b.expand(P);
  102.     return 0;
  103.   }
  104. }
  105.  
  106. /*
  107.  * Moves the turtle in the current direction with respect to the
  108.  * activated hull. If the turtle hits the hull it changes direction.
  109.  * This is repeated until step == 0.
  110.  */
  111.  
  112. int Turtle::forwardWithRespectToHull(real step)
  113. {
  114.   hull->intersect(Ray(P, H), distanceToClosestObject, closestObject);
  115.  
  116.   while (step > 0) {
  117.     if (distanceToClosestObject > step) {
  118.       P += H*step;
  119.       b.expand(P);
  120.       applyTropism();
  121.       distanceToClosestObject -= step;
  122.       break;
  123.     }
  124.     else {
  125.       P += H*distanceToClosestObject;
  126.       b.expand(P);
  127.  
  128.       if (stopOnHit)
  129.     return 1;
  130.  
  131.       bounce();
  132.       applyTropism();
  133.       step -= distanceToClosestObject;
  134.       hull->intersect(Ray(P, H), distanceToClosestObject, closestObject);
  135.     }
  136.   }
  137.  
  138.   return 0;
  139. }
  140.  
  141. /*
  142.  * Reflect turtle at the current closest object -> changes H, U
  143.  */
  144.  
  145. void Turtle::bounce()
  146. {
  147.   /*
  148.    * Reflect turtle at position P. The result is a new heading (H)
  149.    * and a changed up vector (U). The left vector (L) does not change
  150.    * (a reflected ray stays in the same plane).
  151.    */
  152.  
  153.   Vector normal = closestObject->getNormal(P);
  154.  
  155.   H = H-2.*((normal^H)*normal)*reflectanceFactor; 
  156.   H.normalize();
  157.   U = H*L;
  158. }
  159.  
  160. /*
  161.  *  pitch rotates H, L, U around L according to the formula
  162.  *
  163.  *                              [  cos(a)   0   -sin(a) ]
  164.  *                              [                       ]
  165.  *    [H' L' U'] =  [ H L U ] * [     0     1       0   ]
  166.  *                              [                       ]
  167.  *                              [  sin(a)   0   cos(a)  ]
  168.  */
  169.  
  170. void Turtle::pitch(real a)
  171. {
  172.   Vector tmp(H);
  173.   real sin_a, cos_a;
  174.  
  175.   SinCos(a, sin_a, cos_a);
  176.   
  177.   H = H*cos_a + U*sin_a;  
  178.   H.normalize();
  179.   U = U*cos_a - tmp*sin_a;
  180. }
  181.  
  182. /*
  183.  * turn rotates H, L, U around U according to the formula
  184.  *
  185.  *                              [  cos(a)   sin(a)  0 ]
  186.  *                              [                     ]
  187.  *    [H' L' U'] =  [ H L U ] * [ - sin(a)  cos(a)  0 ]
  188.  *                              [                     ]
  189.  *                              [     0        0    1 ]
  190.  */  
  191.   
  192. void Turtle::turn(real a)
  193. {
  194.   Vector tmp(H);
  195.   real sin_a, cos_a;
  196.  
  197.   SinCos(a, sin_a, cos_a);
  198.   
  199.   H = H*cos_a - L*sin_a;   
  200.   H.normalize();
  201.   L = tmp*sin_a + L*cos_a;
  202. }
  203.  
  204. /*
  205.  *  roll rotates H, L, U around H according to the formula
  206.  *
  207.  *                              [  1     0       0     ]
  208.  *                              [                      ]
  209.  *    [H' L' U'] =  [ H L U ] * [  0   cos(a)  sin(a)  ]
  210.  *                              [                      ]
  211.  *                              [  0  -sin(a)  cos(a)  ]
  212.  */
  213.  
  214. void Turtle::roll(real a)
  215. {
  216.   Vector tmp(L);
  217.   real sin_a, cos_a;
  218.  
  219.   SinCos(a, sin_a, cos_a);
  220.   
  221.   L = L*cos_a - U*sin_a;
  222.   U = tmp*sin_a + U*cos_a;
  223. }
  224.  
  225. /*
  226.  *   reverse spins the turtle around 180 degrees
  227.  */
  228.  
  229. void Turtle::reverse()
  230. {
  231.   H = -H;
  232.   L = -L;
  233. }
  234.  
  235. void Turtle::rotate_vertical()
  236. {
  237.   const real tolerance = 1e-4;
  238.   static Vector gravity(0,0,-1);
  239.   Vector tmp = gravity * H;
  240.  
  241.   if (tmp.length() < tolerance)
  242.     return;
  243.  
  244.   L = tmp.normalized();
  245.   U = H*L;
  246. }
  247.   
  248. void Turtle::setWeight(real w)    
  249.   tropism.weight = w; 
  250.   if (equal(tropism.weight, 0) || tropism.F.zero())
  251.     tropism.apply = 0;
  252.   else
  253.     tropism.apply = 1;
  254. }
  255.  
  256. void Turtle::setTropism(real x, real y, real z) 
  257. {
  258.   tropism.F = Vector(x, y, z);
  259.   
  260.   if (!tropism.F.zero()) 
  261.     tropism.F.normalize();
  262.  
  263.   if (equal(tropism.weight, 0) || tropism.F.zero())
  264.     tropism.apply = 0;
  265.   else
  266.     tropism.apply = 1;
  267.  
  268. ostream& operator<<(ostream& os, const Turtle& t)
  269. {
  270.   os << "P: " << t.P << "\n"
  271.      << "H: " << t.H << "\n"
  272.      << "U: " << t.U << "\n"
  273.      << "L: " << t.L << "\n";
  274.   return os;
  275. }
  276.  
  277. /*
  278.  * Apply the given tropism vector to the turtle.
  279.  */
  280.  
  281. void Turtle::applyTropism()
  282. {
  283.   static TransMatrix rot;
  284.  
  285.   /*
  286.    * Should tropism be applied.
  287.    */
  288.   if (!tropism.apply)
  289.     return;
  290.  
  291.   Vector rotvec(H*tropism.F);
  292.   real alpha = acos(H^tropism.F)*tropism.weight*rotvec.length();
  293.  
  294.   /*
  295.    * Limit the rotation.
  296.    */
  297.   if (alpha >  M_PI/6) alpha =  M_PI/6;
  298.   if (alpha < -M_PI/6) alpha = -M_PI/6;
  299.  
  300.   if (!equal(alpha,0) && !rotvec.zero()) {
  301.     rot.setRotate(rotvec, alpha);
  302.     H = H*rot; H.normalize();
  303.     L = L*rot; L.normalize();
  304.     U = H*L;   
  305.   }
  306. }
  307.  
  308.